<template>
  <div
    :class="`${prefixCls}-group-box`"
    v-if="filterGroup"
    :style="{ backgroundColor: getBackgroundColor(filterGroup) }"
  >
    <div :class="`${prefixCls}-group-operate`">
      <template v-for="subGroup in filterGroup.Groups" :key="subGroup">
        <FilterContainer
          :filterGroup="subGroup"
          :parentGroup="filterGroup"
          :properties="entityProperties"
        />
      </template>
      <template v-for="rule in filterGroup.Rules" :key="rule">
        <ARow :class="`${prefixCls}-rule-box`">
          <Select
            size="small"
            v-model:value="rule.Field"
            :dropdownMatchSelectWidth="false"
            style="min-width: 150px"
            show-search
            :placeholder="t('component.adtable.search.selectColumn')"
            :filterOption="filterOption"
            @change="handleRulePropertiesChange(rule)"
          >
            <SelectOption
              v-for="item in entityProperties"
              :key="item.Name"
              :value="item.Name"
              :label="item.Display"
            >
              {{ item.Display }}
            </SelectOption>
          </Select>
          <Select
            size="small"
            style="min-width: 100px; margin-left: 5px"
            v-model:value="rule.Operate"
            :dropdownMatchSelectWidth="false"
            :placeholder="t('component.adtable.search.selectOperate')"
          >
            <SelectOption
              v-for="entity in getFilterOperates(rule)"
              :key="entity.Operate"
              :value="entity.Operate"
              :label="entity.Display"
            >
              {{ entity.Display }}
            </SelectOption>
          </Select>
          <div style="min-width: 200px; margin-left: 5px">
            <template v-for="entityProperty in getEntityProperties(rule)" :key="entityProperty">
              <!-- 枚举类型 -->
              <template v-if="entityProperty.ValueRange?.length > 0">
                <Select
                  v-model:value="rule.Value"
                  :dropdownMatchSelectWidth="false"
                  :showSearch="true"
                  :filterOption="filterOption"
                  :placeholder="t('component.adtable.search.selectValue')"
                  size="small"
                  style="width: 100%; min-width: 100%"
                >
                  <SelectOption
                    v-for="item in entityProperty.ValueRange"
                    :key="item.id"
                    :value="item.id"
                    :label="item.text"
                  >
                    {{ item.text }}
                  </SelectOption>
                </Select>
              </template>
              <!-- 非枚举类型 -->
              <template v-else>
                <!-- 布尔类型 -->
                <template
                  v-if="
                    ['System.Boolean'].find((item) =>
                      entityProperty.TypeName?.match(new RegExp(item, 'gi')),
                    )
                  "
                >
                  <Switch v-model:checked="rule.Value" size="small" />
                </template>
                <!-- 数值类型 -->
                <template
                  v-else-if="
                    ['System.Decimal', 'System.Double'].find((item) =>
                      entityProperty.TypeName?.match(new RegExp(item, 'gi')),
                    )
                  "
                >
                  <InputNumber
                    v-model:value="rule.Value"
                    :placeholder="t('component.adtable.search.inputNumber')"
                    size="small"
                    style="width: 100%; min-width: 100%"
                  />
                </template>
                <!-- 日期时间类型 -->
                <template
                  v-else-if="
                    ['System.DateTime'].find((item) =>
                      entityProperty.TypeName?.match(new RegExp(item, 'gi')),
                    )
                  "
                >
                  <DatePicker
                    v-model:value="rule.Value"
                    :placeholder="t('component.adtable.search.selectDateTime')"
                    size="small"
                    style="width: 100%; min-width: 100%"
                  />
                </template>
                <!-- Guid、整数、字符类型 -->
                <template
                  v-else-if="
                    [
                      'System.Guid',
                      'System.Int16',
                      'System.Int32',
                      'System.Int64',
                      'System.String',
                    ].find((item) => entityProperty.TypeName?.match(new RegExp(item, 'gi')))
                  "
                >
                  <!-- 用户、组织机构、部门类型 -->
                  <template v-if="entityProperty.Flags?.length > 0">
                    <!-- 用户、组织机构、部门类型（当操作符为等于时） -->
                    <template
                      v-if="
                        rule.Operate === FilterOperateEnum.Equal ||
                        rule.Operate === FilterOperateEnum.NotEqual
                      "
                    >
                      <Select
                        v-model:value="rule.Value"
                        :dropdownMatchSelectWidth="false"
                        :showSearch="true"
                        :filterOption="filterOption"
                        :placeholder="t('component.adtable.search.selectValue')"
                        size="small"
                        style="width: 100%; min-width: 100%"
                      >
                        <SelectOption
                          v-for="enumSchema in getFlagsEnumSchema(entityProperty.Flags)"
                          :key="enumSchema.key"
                          :value="enumSchema.value"
                          :label="enumSchema.label"
                        >
                          {{ enumSchema.label }}
                        </SelectOption>
                      </Select>
                    </template>
                    <!-- 短整数类型 -->
                    <template
                      v-else-if="
                        ['System.Int16', 'System.Int32'].find((item) =>
                          entityProperty.TypeName?.match(new RegExp(item, 'gi')),
                        )
                      "
                    >
                      <InputNumber
                        v-model:value="rule.Value"
                        :precision="0"
                        :placeholder="t('component.adtable.search.inputInteger')"
                        size="small"
                        style="width: 100%; min-width: 100%"
                      />
                    </template>
                    <!-- 长整数类型 -->
                    <template
                      v-else-if="
                        ['System.Int64'].find((item) =>
                          entityProperty.TypeName?.match(new RegExp(item, 'gi')),
                        )
                      "
                    >
                      <Input
                        v-model:value="rule.Value"
                        :placeholder="t('component.adtable.search.inputInteger')"
                        size="small"
                        style="width: 100%; min-width: 100%"
                        onkeyup="value=value.replace(/[^{1,2,3,4,5,6,7,8,9,0}]/g,'')"
                      />
                    </template>
                    <!-- 其他字符类型 -->
                    <template v-else>
                      <Input
                        v-model:value="rule.Value"
                        :placeholder="t('component.adtable.search.inputString')"
                        size="small"
                        style="width: 100%; min-width: 100%"
                      />
                    </template>
                  </template>
                  <!-- 短整数类型 -->
                  <template
                    v-else-if="
                      ['System.Int16', 'System.Int32'].find((item) =>
                        entityProperty.TypeName?.match(new RegExp(item, 'gi')),
                      )
                    "
                  >
                    <InputNumber
                      v-model:value="rule.Value"
                      :precision="0"
                      :placeholder="t('component.adtable.search.inputInteger')"
                      size="small"
                      style="width: 100%; min-width: 100%"
                    />
                  </template>
                  <!-- 长整数类型 -->
                  <template
                    v-else-if="
                      ['System.Int64'].find((item) =>
                        entityProperty.TypeName?.match(new RegExp(item, 'gi')),
                      )
                    "
                  >
                    <Input
                      v-model:value="rule.Value"
                      :placeholder="t('component.adtable.search.inputInteger')"
                      size="small"
                      style="width: 100%; min-width: 100%"
                      onkeyup="value=value.replace(/[^{1,2,3,4,5,6,7,8,9,0}]/g,'')"
                    />
                  </template>
                  <!-- 其他字符类型 -->
                  <template v-else>
                    <Input
                      v-model:value="rule.Value"
                      :placeholder="t('component.adtable.search.inputString')"
                      size="small"
                      style="width: 100%; min-width: 100%"
                    />
                  </template>
                </template>
                <!-- 其他类型 -->
                <template v-else>
                  <Input
                    v-model:value="rule.Value"
                    :placeholder="t('component.adtable.search.inputString')"
                    size="small"
                    style="width: 100%; min-width: 100%"
                  />
                </template>
              </template>
            </template>
          </div>
          <Tooltip :title="t('component.adtable.search.removeRule')" placement="top">
            <Button
              size="small"
              style="margin-left: 5px"
              shape="circle"
              @click="handleRemoveRule(rule, filterGroup)"
            >
              <Icon icon="ant-design:close-outlined" />
            </Button>
          </Tooltip>
        </ARow>
      </template>

      <Select :value="filterGroup.Operate" size="small" :dropdownMatchSelectWidth="false">
        <SelectOption
          v-for="entity in groupOperateEntities"
          :key="entity.Operate"
          :value="entity.Operate"
          :label="entity.Display"
        >
          {{ entity.Display }}
        </SelectOption>
      </Select>
      <Button size="small" style="margin-left: 5px" @click="handleAddGroup(filterGroup)">
        <Icon icon="bx:bx-add-to-queue" />{{ t('component.adtable.search.addGroup') }}
      </Button>
      <Button size="small" style="margin-left: 5px" @click="handleAddRule(filterGroup)">
        <Icon icon="ic-outline-rule" />{{ t('component.adtable.search.addRule') }}
      </Button>
      <Button
        size="small"
        style="margin-left: 5px"
        v-if="filterGroup.Level > 1"
        @click="handleRemoveGroup(filterGroup, parentGroup)"
      >
        <Icon icon="subway:remove-playlist" />{{ t('component.adtable.search.removeGroup') }}
      </Button>
    </div>
  </div>
</template>
<script lang="ts" setup>
  import type { PropType } from 'vue';
  import { ref, watchEffect } from 'vue';
  import { useDesign } from '@/hooks/web/useDesign';
  import { useRootSetting } from '@/hooks/setting/useRootSetting';
  import {
    Row,
    Button,
    Select,
    InputNumber,
    Input,
    Switch,
    DatePicker,
    Tooltip,
  } from 'ant-design-vue';
  import { isFunction } from '@/utils/is';
  import { propTypes } from '@/utils/propTypes';
  import Icon from '@/components/Icon/Icon.vue';

  import { useI18n } from '@/hooks/web/useI18n';

  import { FilterRule, FilterGroup, EnumSchema } from '@/utils/common/types';
  import { getOperateEntities } from '@/utils/common';
  import { FilterOperateEnum, FilterOperateEntity } from '@/enums/filterOperateEnum';
  import { EntityProperty } from '@/api/model';

  import { getUserFlagEnumSchema } from '@/enums/userFlagEnum';
  import { getOrganizationFlagEnumSchema } from '@/enums/organizationFlagEnum';
  import { getDepartmentFlagEnumSchema } from '@/enums/departmentFlagEnum';
  import { EntityPropertyFlagEnum } from '@/enums/entityPropertyFlagEnum';

  const ARow = Row;
  const SelectOption = Select.Option;

  defineOptions({ name: 'FilterContainer' });
  const props = defineProps({
    /** 查询条件组 */
    filterGroup: {
      type: Object as PropType<FilterGroup>,
      default: null,
    },
    /** 父级查询条件组 */
    parentGroup: {
      type: Object as PropType<FilterGroup>,
      default: null,
    },
    /** 实体类型名称 */
    entityType: propTypes.string.def(''),
    /** 实体属性配置 */
    properties: {
      type: [Array] as PropType<EntityProperty[]>,
      default: () => [],
    },
    /** 获取实体属性配置API */
    getPropertiesApi: {
      type: Function as PropType<(typeName: string) => Promise<EntityProperty[]>>,
      default: null,
    },
  });

  const { t } = useI18n();
  const { getDarkMode } = useRootSetting();
  const { prefixCls } = useDesign('filter-group');

  const groupOperateEntities = ref<FilterOperateEntity[]>([
    new FilterOperateEntity(FilterOperateEnum.And),
    new FilterOperateEntity(FilterOperateEnum.Or),
  ]);

  /** 获取背景色 */
  function getBackgroundColor(filterGroup: FilterGroup) {
    if (getDarkMode.value === 'dark') {
      return filterGroup.Level % 2 == 0 ? '#151515' : '#1e1e1e';
    } else {
      return filterGroup.Level % 2 == 0 ? '#eee' : '#fff';
    }
  }

  const entityProperties = ref<EntityProperty[]>(props.properties);

  watchEffect(async () => {
    const { filterGroup, entityType, properties, getPropertiesApi } = props;
    if (filterGroup && (!filterGroup.Level || filterGroup.Level === 1)) {
      FilterGroup.Init(filterGroup);
    }
    if (getPropertiesApi && isFunction(getPropertiesApi)) {
      entityProperties.value = await getPropertiesApi(entityType);
    } else {
      entityProperties.value = properties;
    }
    if (entityProperties.value === undefined || entityProperties.value === null) {
      entityProperties.value = [];
    }
  });

  /** 处理条件-属性选择 */
  function handleRulePropertiesChange(rule: FilterRule) {
    // console.log(rule);
    if (!rule) {
      return;
    }
    const property = getEntityProperty(rule);
    if (!property) {
      return;
    }
    const entities = getFilterOperates(rule);
    if (['System.Boolean'].find((item) => property.TypeName?.match(new RegExp(item, 'gi')))) {
      rule.Operate = entities[0]?.Operate;
      rule.Value = rule.Value === true ? true : false;
    } else if (['System.Guid'].find((item) => property.TypeName?.match(new RegExp(item, 'gi')))) {
      rule.Operate = entities[0]?.Operate;
      rule.Value = '';
    } else if (
      ['System.Int16', 'System.Int32', 'System.Int64'].find((item) =>
        property.TypeName?.match(new RegExp(item, 'gi')),
      )
    ) {
      if (property.ValueRange.length === 0) {
        // 整数类型
        rule.Operate = entities[0]?.Operate;
        rule.Value = null;
      } else {
        // 枚举类型
        rule.Operate = entities[0]?.Operate;
        rule.Value = property.ValueRange[0].id || null;
      }
    } else if (
      ['System.Decimal', 'System.Double'].find((item) =>
        property.TypeName?.match(new RegExp(item, 'gi')),
      )
    ) {
      // 数值类型
      rule.Operate = entities[0]?.Operate;
      rule.Value = null;
    } else if (
      ['System.DateTime'].find((item) => property.TypeName?.match(new RegExp(item, 'gi')))
    ) {
      rule.Operate = entities[0]?.Operate;
      rule.Value = null;
    } else if (['System.String'].find((item) => property.TypeName?.match(new RegExp(item, 'gi')))) {
      rule.Operate = FilterOperateEnum.Contains;
      rule.Value = null;
    } else {
      rule.Value = null;
    }
    if (!rule.Operate || entities.filter((m) => m.Operate === rule.Operate).length === 0) {
      rule.Operate = entities[0].Operate;
    }
  }
  /** 处理下拉框筛选 */
  const filterOption = (input: string, option: any) => {
    return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0;
  };

  /** 处理增加分组 */
  function handleAddGroup(group: FilterGroup) {
    const subGroup = new FilterGroup();
    subGroup.Level = group.Level + 1;
    group.Groups.push(subGroup);
  }
  /** 处理删除分组 */
  function handleRemoveGroup(group: FilterGroup, parentGroup: FilterGroup) {
    if (parentGroup) {
      const index = parentGroup.Groups.indexOf(group);
      if (index >= 0) {
        parentGroup.Groups.splice(index, 1);
      }
    }
  }

  /** 处理增加条件 */
  function handleAddRule(group: FilterGroup) {
    const rule = new FilterRule(undefined, null);
    if (entityProperties.value.length > 0) {
      rule.Field = entityProperties.value[0].Name;
      handleRulePropertiesChange(rule);
    }
    group.Rules.push(rule);
  }
  /** 处理删除条件 */
  function handleRemoveRule(rule: FilterRule, group: FilterGroup) {
    // console.log('rule', rule);
    // console.log('group', group);
    if (rule) {
      const index = group.Rules.indexOf(rule);
      if (index >= 0) {
        group.Rules.splice(index, 1);
      }
    }
  }

  /** 获取实体属性 */
  function getEntityProperty(rule: FilterRule): EntityProperty {
    const property = entityProperties.value.find((n) => n.Name === rule.Field) as EntityProperty;
    return property;
  }
  /** 获取实体属性集合 */
  function getEntityProperties(rule: FilterRule): EntityProperty[] {
    const property = entityProperties.value.find((n) => n.Name === rule.Field) as EntityProperty;
    if (property === undefined || property === null) {
      return [];
    }
    return [property];
  }
  /** 获取筛选条件枚举集合 */
  function getFilterOperates(rule: FilterRule): FilterOperateEntity[] {
    let entities: FilterOperateEntity[] = [];
    const property = getEntityProperty(rule);
    if (property === undefined || property === null) {
      return entities;
    }
    // property.TypeName = property.TypeName ? property.TypeName : 'System.String';
    if (['System.Boolean'].find((item) => property.TypeName?.match(new RegExp(item, 'gi')))) {
      entities = getOperateEntities([FilterOperateEnum.Equal, FilterOperateEnum.NotEqual]);
    } else if (['System.Guid'].find((item) => property.TypeName?.match(new RegExp(item, 'gi')))) {
      entities = getOperateEntities([FilterOperateEnum.Equal, FilterOperateEnum.NotEqual]);
    } else if (
      ['System.Int16', 'System.Int32', 'System.Int64'].find((item) =>
        property.TypeName?.match(new RegExp(item, 'gi')),
      )
    ) {
      if (property.ValueRange.length === 0) {
        // 整数类型
        entities = getOperateEntities([
          FilterOperateEnum.Equal,
          FilterOperateEnum.NotEqual,
          FilterOperateEnum.Less,
          FilterOperateEnum.LessOrEqual,
          FilterOperateEnum.Greater,
          FilterOperateEnum.GreaterOrEqual,
        ]);
      } else {
        // 枚举类型
        entities = getOperateEntities([FilterOperateEnum.Equal, FilterOperateEnum.NotEqual]);
      }
    } else if (
      ['System.Decimal', 'System.Double'].find((item) =>
        property.TypeName?.match(new RegExp(item, 'gi')),
      )
    ) {
      // 数值类型
      entities = getOperateEntities([
        FilterOperateEnum.Equal,
        FilterOperateEnum.NotEqual,
        FilterOperateEnum.Less,
        FilterOperateEnum.LessOrEqual,
        FilterOperateEnum.Greater,
        FilterOperateEnum.GreaterOrEqual,
      ]);
    } else if (
      ['System.DateTime'].find((item) => property.TypeName?.match(new RegExp(item, 'gi')))
    ) {
      entities = getOperateEntities([
        FilterOperateEnum.Equal,
        FilterOperateEnum.NotEqual,
        FilterOperateEnum.Less,
        FilterOperateEnum.LessOrEqual,
        FilterOperateEnum.Greater,
        FilterOperateEnum.GreaterOrEqual,
      ]);
    } else if (['System.String'].find((item) => property.TypeName?.match(new RegExp(item, 'gi')))) {
      entities = getOperateEntities([
        FilterOperateEnum.Equal,
        FilterOperateEnum.NotEqual,
        FilterOperateEnum.StartsWith,
        FilterOperateEnum.EndsWith,
        FilterOperateEnum.Contains,
        FilterOperateEnum.NotContains,
      ]);
    } else {
      entities = getOperateEntities([
        FilterOperateEnum.Equal,
        FilterOperateEnum.NotEqual,
        FilterOperateEnum.Less,
        FilterOperateEnum.LessOrEqual,
        FilterOperateEnum.Greater,
        FilterOperateEnum.GreaterOrEqual,
        FilterOperateEnum.StartsWith,
        FilterOperateEnum.EndsWith,
        FilterOperateEnum.Contains,
        FilterOperateEnum.NotContains,
      ]);
    }
    return entities;
  }

  /** 获取标记集合枚举架构 */
  function getFlagsEnumSchema(flags: EntityPropertyFlagEnum[]) {
    let outFlags: EnumSchema[] = [];
    flags.forEach((item) => {
      switch (item) {
        case EntityPropertyFlagEnum.UserFlag:
          outFlags.push(...getUserFlagEnumSchema());
          break;
        case EntityPropertyFlagEnum.OrganizationFlag:
          outFlags.push(...getOrganizationFlagEnumSchema());
          break;
        case EntityPropertyFlagEnum.DepartmentFlag:
          outFlags.push(...getDepartmentFlagEnumSchema());
          break;
      }
    });
    return outFlags;
  }
</script>
<style lang="less">
  @prefix-cls: ~'@{namespace}-filter-group';

  .@{prefix-cls} {
    &-group-box {
      margin: 2px;
      padding: 3px;
      border: dashed 2px #ddd;
    }

    &-group-operate {
      margin: 3px 0;
    }

    &-rule-box {
      margin: 3px;
    }
  }

  [data-theme='dark'] {
    .@{prefix-cls} {
      &-group-box {
        border: dashed 2px #303030;
      }
    }
  }
</style>
